﻿using System.Collections.Generic;
using System.Data;
using System.Globalization;
using System.Linq;
using CollegeSim.Domain.DTO;
using CollegeSim.Domain.Interfaces.Services;

namespace CollegeSim.CourseScheduler.Presentation.Facade
{
    // Author: Ryan Redburn
    // Project: Course Scheduler
    // Date: 2/12/2014

    #region [ Updates ]

    // Author: Ryan Redburn
    // Date: 4/6/2014
    // Revisions: Added delete functionality and additional comments.

    // Author: Ryan Redburn
    // Date: 5/12/2014
    // Revisions: Changed facade to reflect version 2.0 changes.

    // Author: Ryan Redburn
    // Date: 5/19/2014
    // Revisions: Changed GetCourseFromtempStore to use an ID value rather than index.

    #endregion

    public sealed class SchedulerFacade
    {
        #region [ Fields ]
        
        // Domain Services
        private readonly ICourseService _courseService;
        private readonly IInstructorService _instructorService;

        // Temp Data Stores
        private List<CourseDTO> _courses;
        private List<InstructorDTO> _instructors; 

        #endregion

        #region [ Constructors ]

        // Prepare Facade on instantiation
        public SchedulerFacade(ICourseService courseService, IInstructorService instructorService)
        {
            _courseService = courseService;
            _instructorService = instructorService;

            // Initialize temp data
            GetTempData();
        }

        #endregion

        #region [ Methods ]

        #region [ General ]

        /// <summary>
        /// Initailizes temporary data for facade use.
        /// </summary>
        private void GetTempData()
        {
            _courses = _courseService.GetAll();
            _instructors = _instructorService.GetAll();
        }

        #endregion

        #region [ Course ]

        /// <summary>
        /// Creates a new course.
        /// </summary>
        /// <param name="subject">Three character course subject.</param>
        /// <param name="number">Three character course number</param>
        /// <param name="title">Course title.</param>
        /// <param name="creditHours">Number of course credit hours. Must be in the range of 1-6.</param>
        /// <param name="contactHours">Number of contact hours. Must be in the range of 1-6.</param>
        /// <param name="online">Course style online.</param>
        /// <param name="hybrid">Course style hybrid.</param>
        public void CreateCourse(string subject, string number, string title, int creditHours, int contactHours, bool online, bool hybrid)
        {
            // New Course
            var newCourse = new CourseDTO
            {
                Subject = subject,
                Number = number,
                Title = title,
                CreditHours = (byte)creditHours,
                ContactHours = (byte)contactHours,
                Online = online,
                Hybrid = hybrid
            };

            // Giving new Course to the CourseService for validation and persistence
            _courseService.Commit(newCourse);

            // Refresh temp data
            GetTempData();
        }

        /// <summary>
        /// Uodates an existing course.
        /// </summary>
        /// <param name="id">Integer ID of course to update.</param>
        /// <param name="subject">Three character course subject.</param>
        /// <param name="number">Three character course number.</param>
        /// <param name="title">Course title.</param>
        /// <param name="creditHours">Number of course credit hours. Must be in the range of 1-6.</param>
        /// <param name="contactHours">Number of contact hours. Must be in the range of 1-6.</param>
        /// <param name="online">Course style online.</param>
        /// <param name="hybrid">Course syle hybrid.</param>
        public void UpdateCourse(int id, string subject, string number, string title, int creditHours, int contactHours, bool online, bool hybrid)
        {
            // Course to update
            var courseUpdate = new CourseDTO
            {
                CourseID = id,
                Number = number,
                Subject = subject,
                Title = title,
                CreditHours = (byte)creditHours,
                ContactHours = (byte)contactHours,
                Online = online,
                Hybrid = hybrid
            };

            // Giving updated Course to the CourseService for validation and persistence
            _courseService.Update(id, courseUpdate);

            // Refresh temp data
            GetTempData();
        }

        /// <summary>
        /// Deletes an existing course.
        /// </summary>
        /// <param name="courseId">Interger id.</param>
        public void DeleteCourse(int courseId)
        {
            // Retrieve the selected course and submit it for deletion
            var course = _courseService.GetByID(courseId);
            _courseService.Delete(course);

            // Refresh temp data
            GetTempData();
        }

        /// <summary>
        /// Returns a course from the temporary data store using the ID value.
        /// </summary>
        /// <param name="courseID">CourseID.</param>
        /// <returns>List of string course information. CourseID, subject, course number, title, creditshours, contacthours, is online, is hybrid.</returns>
        public List<string> GetCourseFromTempStore(int courseID)
        {
            // Retrieves course from temp data store
            var course = _courses.SingleOrDefault(c => c.CourseID == courseID);

            // Create string list with course info
            var courseInfo = new List<string>
            {
                course.CourseID.ToString(CultureInfo.InvariantCulture),
                course.Subject,
                course.Number,
                course.Title,
                course.CreditHours.ToString(CultureInfo.InvariantCulture),
                course.ContactHours.ToString(CultureInfo.InvariantCulture),
                course.Online ? "Yes" : "No",
                course.Hybrid ? "Yes" : "No"
            };

            return courseInfo;
        }

        /// <summary>
        /// Gets a course using the given id.
        /// </summary>
        /// <param name="id">Interger course id</param>
        /// <returns>List of string course information. CRN, subject, course number, title, creditshours, contacthours, is online, instructor last name.</returns>
        public List<string> GetCourseByID(int id)
        {
            // Retrieve course using given id
            var course = _courseService.GetByID(id);

            // Create string list with course info
            var courseInfo = new List<string>
            {
                course.Subject,
                course.Number,
                course.Title,
                course.CreditHours.ToString(CultureInfo.InvariantCulture),
                course.ContactHours.ToString(CultureInfo.InvariantCulture),
                course.Online ? "Yes" : "No",
                course.Hybrid ? "Yes" : "No"
            };

            return courseInfo;
        }

        /// <summary>
        /// Returns a list of string course representations.
        /// </summary>
        /// <returns>String list, CourseID + Subject + Number + Title</returns>
        public List<string> GetCourseList()
        {
            // Retrieve list of courses
            var courses = _courseService.GetAll();

            // Create string list of courses for return
            return courses.Select(c => c.CourseID + " - " + c.Subject + c.Number + " - " + c.Title).ToList();

        }

        /// <summary>
        /// Returns a table containing all courses.
        /// </summary>
        /// <returns>DataTable of Course info.</returns>
        public DataTable GetCourseTable()
        {
            // Retrieve table resources
            var courses = _courseService.GetAll();

            // Create course table
            var courseTable = new DataTable();
            courseTable.Columns.Add("CourseID", typeof (int));
            courseTable.Columns.Add("Subject", typeof (string));
            courseTable.Columns.Add("Number", typeof (string));
            courseTable.Columns.Add("Title", typeof (string));
            courseTable.Columns.Add("Credit Hours", typeof (int));
            courseTable.Columns.Add("Contact Hours", typeof (int));
            courseTable.Columns.Add("Online", typeof (bool));
            courseTable.Columns.Add("Hybrid", typeof (bool));

            // Add course rows
            foreach (var c in courses)
            {
                courseTable.Rows.Add(c.CourseID, c.Subject, c.Number, c.Title, c.CreditHours, c.ContactHours,
                    c.Online, c.Hybrid);
            }

            return courseTable;
        }

        #endregion

        #region [ Instructor ]

        /// <summary>
        /// Creates a new instructor.
        /// </summary>
        /// <param name="firstName">Instructor first name.</param>
        /// <param name="lastName">instructor last name</param>
        /// <param name="phoneNumber">Instructor phone number</param>
        /// <param name="email">Instructor email.</param>
        /// <param name="officeNumber">Instructor office number.</param>
        public void CreateInstructor(string firstName, string lastName, string phoneNumber = null, string email = null, string officeNumber = null)
        {
            // New Instructor
            var newInstructor = new InstructorDTO
            {
                FirstName = firstName,
                LastName = lastName,
                PhoneNumber = phoneNumber,
                Email = email,
                OfficeNumber = officeNumber
            };

            // Giving new Instructor to the InstructorService for validation and persistence
            _instructorService.Commit(newInstructor);
        }

        /// <summary>
        /// Returns a list of string instructor representations.
        /// </summary>
        /// <returns>String list, "id - lastname, firstname".</returns>
        public List<string> GetInstructorList()
        {
            var instructors = _instructorService.GetAll();
            return instructors.Select(i => i.InstructorID + " - " + i.LastName + ", " + i.FirstName).ToList();
        }

        #endregion

        #endregion
    }
}
